#include "TreeMap.h""

Squarify::Squarify(){}

QVector<SqOutput> Squarify::getSquarified(QRectF rc,const QVector<SqInput>& values,bool bClacRate)
{
    currentInput = values;
    if(bClacRate)
    {
        double currentValue;
        for(int i=0;i <= currentInput.size()-1;i++)
        {
            currentValue += currentInput[i].value;
        }
        currentValue = rc.width()*rc.height()/currentValue;
        for(int i=0;i <= currentInput.size()-1;i++)
        {
            currentInput[i].value *= currentValue;
        }
    }
    unfilledRc =  rc;
    currentRc = rc;
    squarify(currentInput,QVector<SqInput>());
    return completedOutput;
}

void Squarify::squarify(const QVector<SqInput> &inputs, const QVector<SqInput> &currValues)
{
    if(unfilledRc.isEmpty())
        return;
    if(inputs.isEmpty())
    {
        if(!currValues.isEmpty())
        {
            layoutRects(currValues);
        }
        return;
    }
    SqInput c = inputs[0];
    QVector<SqInput> newrow = currValues;
    newrow.push_back(c);
    if(calcWHrate(newrow) < calcWHrate(currValues))
    {
        QVector<SqInput> temp = inputs.mid(1);
        squarify(temp,newrow);
    }
    else
    {
        layoutRects(currValues);
        squarify(inputs,QVector<SqInput>());
    }
}

void Squarify::layoutRects(const QVector<SqInput> &preValues)
{
    double fixedWidth = unfilledRc.width();
    bool bhorizon = false;
    if(unfilledRc.width() > unfilledRc.height())
    {
        bhorizon = true;
        fixedWidth = unfilledRc.height();
    }
    double allAcreage = 0;
    for(SqInput value:preValues)
    {
        allAcreage += value.value;
    }
    double oneSide = allAcreage/fixedWidth;
    QRectF rc = unfilledRc;
    QRectF emptyRc;
    double tempValue1 = DBL_MAX,tempValue2 = DBL_MAX;
    SqOutput item;
    for(int i= preValues.size()-1;i >= 0;i--)
    {
        if(bhorizon)
        {
            if(tempValue2 == DBL_MAX)
            {
                tempValue2 = unfilledRc.bottom();
                emptyRc = unfilledRc;
                emptyRc.setLeft(unfilledRc.left() + oneSide);
            }
            tempValue1 = preValues[i].value/oneSide;
            rc.setLeft(unfilledRc.left());
            rc.setTop(tempValue2-tempValue1);
            rc.setWidth(oneSide);
            rc.setHeight(tempValue1);
            item.rectangle = rc;
            item.ptr =  preValues[i].ptr;
            completedOutput.push_back(item);
            tempValue2 -= tempValue1;
        }
        else
        {
            if(tempValue2 == DBL_MAX)
            {
                emptyRc = unfilledRc;
                emptyRc.setBottom(unfilledRc.bottom()-oneSide);
                tempValue2 = unfilledRc.right();
            }
            tempValue1 = preValues[i].value/oneSide;
            rc.setLeft(tempValue2-tempValue1);
            rc.setTop(unfilledRc.bottom()-oneSide);
            rc.setWidth(tempValue1);
            rc.setHeight(oneSide);
            item.rectangle = rc;
            item.ptr = preValues[i].ptr;
            completedOutput.push_back(item);
            tempValue2 -= tempValue1;
        }
    }
    unfilledRc = emptyRc;
}

double Squarify::calcWHrate(const QVector<SqInput> &currValues)
{
    if(currValues.isEmpty())
        return DBL_MAX;
    double fixedWidth = unfilledRc.width();
    if(unfilledRc.width() > unfilledRc.height())
    {
        fixedWidth = unfilledRc.height();
    }
    double allAcreage = 0;
    for(SqInput r:currValues)
    {
        allAcreage += r.value;
    }
    double retValue = 0;
    double side = 0;
    for(auto r:currValues)
    {
        side = allAcreage/fixedWidth;
        retValue =  std::max(retValue,std::max(r.value/side/side,side/(r.value/side)));
    }
    return retValue;
}
